package com.cx.web.interceptor;

import com.alibaba.fastjson.JSON;
import com.cx.common.cons.CharacterCons;
import com.cx.common.util.*;
import com.cx.meta.exception.CxErrorCode;
import com.cx.meta.exception.ErrorResponse;
import com.cx.meta.cache.CxCommonCache;
import com.cx.web.config.CxUrlConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import redis.clients.jedis.Jedis;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

/**
 * @author flysand
 * @package com.cx.web.interceptor
 * @date 2021-11-12 01:56
 * @des CxInterceptor:好像没用 好吧 -- 通过response进行返回数据和重定向
 */
public class CxInterceptor implements HandlerInterceptor {

    private final static Logger logger = LoggerFactory.getLogger(CxInterceptor.class);

    private final static String[] ESCAPE_URLS = {"login", "register", "www/"};


    @Resource(name = "urlConfig")
    private CxUrlConfig urlConfig;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 跳过chrome预检 options请求
        if (CorsUtils.isPreFlightRequest(request)) {
            // chrome会对添加了header的请求进行跨域options预检
            // 但options请求header没有要校验的header，所以会校验不通过，需要跳过 预检  直接return true跳过校验
            return true;
        }

        String token = request.getHeader("token");
        String url = request.getRequestURI();
        logger.info("url：" + url + ",token:" + token);


        // 跳过login和register
        if (CollectionUtils.containsIgnoreCase(url, Arrays.asList(ESCAPE_URLS))) {
            // 跳过
            logger.debug("当前url不做校验：" + url);
            return true;
        }


        if (StringUtils.isBlank(token)) {
//            throw new CxException(CxErrorCode.ACCESS_LIMIT);
            // 通过httpResponse返回
            handlerResponse(response, CxErrorCode.UN_LOGIN);
            logger.debug("token is null");
            // handlerRedirect(response, urlConfig.getLoginView());
            return false;
        }
        // token过期
        Jedis jedis = JedisUtils.connRedis();
        String val = jedis.get(token);
        if (StringUtils.isEmpty(val)) {
            // token不存在
            logger.debug("token has expired");
            handlerResponse(response, CxErrorCode.TOKEN_EXPIRED);
            // handlerRedirect(response, urlConfig.getLoginView());
            return false;
        }

        // token value 不正确  其他地方登录  暂时根据ip判断   手机端可以根据手机标识
        String ip = IpUtils.getIp(request);

        if (!Md5Utils.md5(ip).equals(val.split(CharacterCons.UNDER_LINE)[0])) {
            logger.info("用户在其他地方登录：" + ip);
            handlerResponse(response, CxErrorCode.OTHER_LOGIN);
            // handlerRedirect(response, urlConfig.getLoginView());
            return false;
        }
        logger.debug("请求token校验通过：" + url);
        CxCommonCache.TOKEN_MAP.put(token, val);
        return true;
    }


    /**
     * token验证失败的处理
     *
     * @param response
     * @param errorCode
     * @throws IOException
     */
    private void handlerResponse(HttpServletResponse response, CxErrorCode errorCode) throws IOException {
        ErrorResponse errorResponse = new ErrorResponse(errorCode);
        response.setContentType("application/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.print(JSON.toJSONString(errorResponse));
        writer.close();
        // response.sendRedirect("/");
    }

    /**
     * HttpServletResponse 有两种方式获得输出流  ==  注意流只能使用一个  并记得使用完关闭流
     * 1、PrintWrite out = response.getWriter(); writer.print();  用于输出字符流数据
     * 2、ServletOutputStream os = response.getOutputStream(); 用于输出二禁止字节流数据  比如excel表格导出
     */
    private static void handler() {

    }

    /**
     * 重定向页面
     */
    private void handlerRedirect(HttpServletResponse response, String url) throws IOException {
        logger.debug("重定向：" + url);
        response.sendRedirect(StringUtils.isBlank(url) ? urlConfig.getLoginView() : url);
    }
}
